#pragma once

#include <stdint.h>
#include <string>

using std::string;

template <class T>
inline T sqr(const T &x)
{
    return x * x;
}

namespace Graph
{

/** @class Vertex.
  * @brief Вершина.
  *
  * Вершина (вектор) в векторной графике.
  */
class Vertex
{
public:

    /**
      * Конструктор по умолчанию.
      */
    Vertex(): x(0.0f), y(0.0f), z(0.0f), color(0)
    {
    }

    /**
      * Конструктор копирования.
      *
      * @param other копируемый вектор.
      */
    Vertex(const Vertex &other): x(other.x), y(other.y), z(other.z),
        color(other.color)
    {
    }

    /**
      * Конструктор.
      *
      * @param x x кордината вершины.
      * @param y y кордината вершины.
      * @param z z кордината вершины.
      * @param color 32х-бтиное представление цвета.
      *              @see Graphics.intColor
      */
    Vertex(const float x, const float y, const float z, const uint32_t color):
        x(x), y(y), z(z), color(color)
    {
    }

    /**
      * Конструктор. Цвет по умочанию - полностью прозрачный белый.
      *
      * @param x x кордината вершины.
      * @param y y кордината вершины.
      * @param z z кордината вершины.
      */
    Vertex(const float x, const float y, const float z): x(x), y(y), z(z),
      color(0)
    {
    }

    /**
      * Конструктор. Цвет по умочанию - полностью прозрачный белый.
      * Координата z по умолчанию - 0.
      *
      * @param x x кордината вершины.
      * @param y y кордината вершины.
      */
    Vertex(const float x, const float y): x(x), y(y), z(0.0f), color(0)
    {
    }

    /**
      * Деструктор.
      */
    ~Vertex()
    {
    }

    /**
      * Возвращает квадрат эвклидовой нормы вектора.
      *
      * @return квадрат нормы.
      */
    float sqrNorm() const;

    /**
      * Возвращает эвклидову норму вектора.
      *
      * @return значение нормы.
      */
    float norm() const;

    /**
      * Масштабирует вектор к единичной норме.
      *
      * @return ссылка на вектор после масшабирования.
      */
    Vertex& normalize();

    /**
      * Создает новый вектор, равный масшабированному исходному.
      * Не изменяет исходный вектор.
      *
      * @return созданный вектор единичной нормы.
      */
    Vertex normalized() const;

    /**
      * Вычисляет векторное произведение.
      *
      * @param v вектор, на котрый производится умножение.
      * @return векторное произведение.
      */
    Vertex vectorProduct(const Vertex &v) const;

    /**
      * Вычисляет векторное произведение 2х векторов.
      *
      * @param v1 первый вектор.
      * @param v2 второй вектор.
      * @return векторное произведение v1 * v2.
      */
    static Vertex vectorProduct(const Vertex &v1, const Vertex &v2);

    /**
      * Умножает все компоненты вектора на константу.
      *
      * @param a множитель.
      * @return вектор после умножения.
      */
    Vertex& operator *=(const float a);

    /**
      * Делит все компоненты вектора на константу.
      *
      * @param a делитель.
      * @return вектор после деления.
      */
    Vertex& operator /=(const float a);

    /**
      * Прибавляет к вектору другой вектор.
      *
      * @param v прибавляемый вектор.
      * @return вектор после сложения.
      */
    Vertex& operator +=(const Vertex& v);

    /**
      * Вчитает из вектора другой вектор.э
      *
      * @param v вычитаемый вектор.
      * @return вектор после вычитания.
      */
    Vertex& operator -=(const Vertex& v);

    /**
      * Возвращает строковое представление вектора.
      *
      * @return строка, отражающее содержимое вектора.
      */
    string toString() const;

public:
    float x, y, z;      ///< Координаты (компоненты) вектора.
    uint32_t color;     ///< 32х-битное представление цвета.
};

/**
  * Покомпонентно складывает 2 вектора.
  *
  * @param v1 первое слагаемое.
  * @param v2 второе слагаемое.
  * @return v1 + v2.
  */
Vertex operator +(const Vertex &v1, const Vertex &v2);

/**
  * Покомпонентно вычитает из одного вектора другой.
  *
  * @param v1 первое слагаемое.
  * @param v2 второе слагаемое.
  * @return v1 - v2.
  */
Vertex operator -(const Vertex &v1, const Vertex &v2);

/**
  * Делит все компоненты вектора на число.
  *
  * @param v делимое.
  * @param a делитель.
  * @return v / a.
  */
Vertex operator /(const Vertex &v, const float a);

/**
  * Умножает все компоненты вектора на число.
  *
  * @param v умножаемый вектор.
  * @param a множитель.
  * @return a * v;
  */
Vertex operator *(const Vertex &v, const float a);

/**
  * Умножает все компоненты вектора на число.
  *
  * @param v умножаемый вектор.
  * @param a множитель.
  * @return a * v;
  */
Vertex operator *(const float a, const Vertex &v);

/**
  * Скалярное произведение векторов.
  *
  * @param v1 первый сомножитель.
  * @param v2 второй сомножитель.
  * @return скалярное произведение v1 и v2.
  */
float operator *(const Vertex &v1, const Vertex &v2);

}
